<template>
  <div class="bf-curd w-full h-full">
    <div class="bf-opera-row pb-2" ref="operaRowEl" :style="{ height: sizeState.oRowHeight }">
      <BFToolRow v-if="!slots['header']">
        <template #left>
          <n-button
            v-for="(item, index) in btns.leftBtns"
            :key="index"
            v-bind="{ ...item.btnProps }"
            @click="pageBtnClickHandler(item)"
          >
            {{ item.text }}
          </n-button>
        </template>
        <template #right>
          <n-button
            v-for="(item, index) in btns.rightBtns"
            :key="index"
            v-bind="{ ...item.btnProps }"
            @click="pageBtnClickHandler(item)"
          >
            {{ item.text }}
          </n-button>
        </template>
      </BFToolRow>

      <slot name="header" v-else />
    </div>
    <div class="bf-table-row" ref="tableEl" :style="{ height: sizeState.tRowHeight }">
      <n-spin :show="state.tableLoading" class="w-full h-full">
        <BFTable
          :data="state.tableData"
          v-bind="props.table"
          v-model:select-row-keys="state.selectRowKeys"
          v-model:select-rows="state.selceRows"
          :scroll-x="sizeState.scrollX"
        >
          <!-- <template v-for="(item, index) in slotsColumnKeys" :key="index" #[item]="{ rowData, rowIndex }">
            <slot :name="item" :rowData="rowData" :rowIndex="rowIndex">
              {{ rowData[item] }}
            </slot>
          </template> -->
          <template #action="{ rowData }" v-if="btns.tableActionBtns && btns.tableActionBtns.length > 0">
            <n-button
              class="mr-2"
              v-for="item in btns.tableActionBtns"
              :key="item.opera"
              v-show="item.show!(rowData)"
              @click="pageBtnClickHandler(item, rowData)"
              v-bind="item.btnProps"
            >
              {{ item.text }}
            </n-button>
          </template>
        </BFTable>
      </n-spin>
    </div>
    <div
      class="page-row flex justify-center"
      ref="pagetionEl"
      :style="{ height: sizeState.pRowHeight, marginTop: '10px' }"
    >
      <NPagination
        v-model:page="state.page"
        v-model:page-size="state.size"
        :page-sizes="[20, 30, 40, 50]"
        :item-count="state.total"
        show-quick-jumper
        show-size-picker
        @update-page="initTableData"
        @update-page-size="initTableData"
      >
        <template #prefix> 共{{ state.total }}条 </template>
      </NPagination>
    </div>
    <BFModal
      v-model:visible="modalVisible"
      title="Basic"
      @ok="pageBtnClickHandler(btns.modalConfirmBtn, null, 'getFormData')"
      @cancle="pageBtnClickHandler(btns.modalCancelBtn)"
      :cancle-text="btns.modalCancelBtn.text"
      :ok-text="btns.modalConfirmBtn.text"
    >
      <BFFormParse
        v-if="props.form"
        :template="templates.modalForm"
        :value="state.formdata"
        ref="modalFormParse"
      />
      <slot name="modalContent" />
    </BFModal>

    <n-drawer v-model:show="filterVisible" :width="502" :placement="'right'">
      <n-drawer-content title="筛选查询">
        <BFFormParse
          v-if="props.form"
          :template="templates.filterForm"
          :value="state.filterData"
          ref="filterFormParse"
        />
        <slot name="drawerContent" />
        <template #footer>
          <n-button
            v-for="(item, index) in btns.drawerFooterBtns"
            :key="index"
            v-bind="item.btnProps"
            :class="[index > 0 ? 'ml-3' : '']"
            @click="pageBtnClickHandler(item, null, 'getFilterData')"
          >
            {{ item.text }}
          </n-button>
        </template>
      </n-drawer-content>
    </n-drawer>
  </div>
</template>

<script setup lang="ts">
import { BFFormParseExpose, BFFormParseProps } from '@/components/bf-form-parse/src/bf-form.parse'
import { BFTableProps } from '@/components/bf-table/src/bf-table'
import { debounce } from '@/utils/common.util'
import { NPagination } from 'naive-ui'
import { computed, onMounted, onUnmounted, reactive, ref, useSlots } from 'vue'
import {
  BFCurdExpose,
  BFCurdOperaBtn,
  createState,
  getDefaultBFCurdBtns,
  initColumns,
  PageBtnClickCallbackFn,
  PageBtnClickData,
  showInfo,
  useFilter,
  useModal,
  OperaBtnKeys
} from './bf-curd'

interface BFCurdProps {
  operaBtns?: {
    toolRow?: BFCurdOperaBtn[]
    modalConfirm?: BFCurdOperaBtn
    modalCancel?: BFCurdOperaBtn
    tableActionColumn?: BFCurdOperaBtn[]
    drawerFooter?: BFCurdOperaBtn[]
  }
  table: BFTableProps
  form?: BFFormParseProps
  r?: (page: number, size: number, otherData?: any) => Promise<{ list: any[]; total: number }>
  c?: (newData: any) => Promise<{ success: boolean; msg: string }>
  u?: (newData: any) => Promise<{ success: boolean; msg: string }>
  d?: (keys: any[]) => Promise<{ success: boolean; msg: string }>
}

interface BFCurdEmits {
  (e: 'page-btn-click', btn: BFCurdOperaBtn, other: PageBtnClickData, callBack?: PageBtnClickCallbackFn): void
}

const props = withDefaults(defineProps<BFCurdProps>(), {
  operaBtns: () => ({})
})

const emits = defineEmits<BFCurdEmits>()
let operaRowEl = ref<HTMLElement>()
let tableEl = ref<HTMLElement>()
let pagetionEl = ref<HTMLElement>()
let modalFormParse = ref<BFFormParseExpose>()
let filterFormParse = ref<BFFormParseExpose>()
const state = createState(props.table)
/* 获取页面默认按钮 */
const defaultBtns = getDefaultBFCurdBtns()
/* 获取页面按钮 */
const btns = computed(() => {
  props.operaBtns.toolRow! = props.operaBtns!.toolRow || defaultBtns.toolRow!
  props.operaBtns.modalConfirm! = props.operaBtns!.modalConfirm || defaultBtns.modalConfirm!
  props.operaBtns.modalCancel! = props.operaBtns!.modalCancel! || defaultBtns.modalCancel
  props.operaBtns.drawerFooter! = props.operaBtns.drawerFooter || defaultBtns.drawerFooter!
  const tableActionBtns: BFCurdOperaBtn[] =
    props.operaBtns!.tableActionColumn || defaultBtns.tableActionColumn!

  const leftBtns: BFCurdOperaBtn[] = []
  const rightBtns: BFCurdOperaBtn[] = []
  props.operaBtns.toolRow!.forEach((item) => {
    if (item.show) {
      if (item.show!() && item.pos! === 'right') {
        rightBtns.push(item)
      }
      if (item.show!() && item.pos! === 'left') {
        leftBtns.push(item)
      }
    } else {
      if (item.pos === 'right') {
        rightBtns.push(item)
      } else {
        leftBtns.push(item)
      }
    }
  })
  return {
    leftBtns: reactive(leftBtns),
    rightBtns: reactive(rightBtns),
    modalConfirmBtn: props.operaBtns!.modalConfirm,
    modalCancelBtn: props.operaBtns!.modalCancel,
    tableActionBtns,
    drawerFooterBtns: props.operaBtns.drawerFooter
  }
})

/* 获取modalForm 和 filterForm */
const templates = computed(() => {
  let modalForm: any[] = []
  let filterForm: any[] = []
  props.form?.template?.forEach((item) => {
    if (item.tabKey != undefined && item.tabKey != '') {
      let t: any[] = []
      item.template?.forEach((temp) => {
        if (temp.pos == undefined) {
          t.push(temp)
          filterForm.push(temp)
        } else {
          temp.pos == 'modal' ? t.push(temp) : filterForm.push(temp)
        }
      })
      modalForm.push({ ...item, template: t })
    } else {
      if (item.pos == undefined) {
        modalForm.push(item)
        filterForm.push(item)
      } else {
        item.pos == 'modal' ? modalForm.push(item) : filterForm.push(item)
      }
    }
  })
  return { modalForm, filterForm }
})
const slots = useSlots()
initColumns(props.table, slots)
const { modalVisible, showModal, hideModal } = useModal()
const { filterVisible, showFilter, hideFilter } = useFilter()

const initTableData = async (otherData?: any) => {
  state.tableLoading = true
  let { list, total } = await props.r!(state.page, state.size, otherData)
  state.tableData = list
  state.total = total
  state.tableLoading = false
}
initTableData()

const pageBtnClickCallBack: PageBtnClickCallbackFn = async (action, info) => {
  if (!action) return
  switch (action) {
    case 'c': {
      let { success, msg } = await props.c!(info)
      return showInfo(success, msg, initTableData)
    }
    case 'u': {
      let { success, msg } = await props.u!(info)
      return showInfo(success, msg, initTableData)
    }
    case 'r':
      initTableData(info)
      break
    case 'd': {
      window.$dialog.warning({
        title: '警告',
        content: info.prompt || '你确定要删除这些项吗?',
        positiveText: '确定',
        negativeText: '取消',
        async onPositiveClick() {
          let { success, msg } = await props.d!(info.data)
          return showInfo(success, msg, initTableData)
        }
      })
      break
    }
  }
}

const pageBtnClickHandler = (
  item: BFCurdOperaBtn,
  rowData: any = null,
  isGetFormData?: 'getFormData' | 'getFilterData'
) => {
  let formdata = null
  if (isGetFormData === 'getFormData') {
    formdata = modalFormParse.value?.getFormData()
  }
  if (isGetFormData === 'getFilterData') {
    formdata = filterFormParse.value?.getFormData()
  }
  emits(
    'page-btn-click',
    item,
    {
      formdata,
      rowData,
      selectKeys: state.selectRowKeys,
      selectRows: state.selceRows
    },
    pageBtnClickCallBack
  )
}

const sizeState = reactive({
  oRowHeight: 'auto',
  tRowHeight: 'auto',
  scrollX: '100%',
  pRowHeight: 'auto'
})

/**
 * 自适应页面组件宽高
 */
const autoResetSize = debounce(
  () => {
    let oRect = operaRowEl.value!.getClientRects()
    let pRect = pagetionEl.value!.getClientRects()
    sizeState.oRowHeight = oRect[0].height.toFixed(0) + 'px'
    sizeState.pRowHeight = pRect[0].height.toFixed(0) + 'px'
    sizeState.tRowHeight = `calc(100% - ${sizeState.oRowHeight} - ${sizeState.pRowHeight} - 10px)`
    sizeState.scrollX = oRect[0].width + 'px'
  },
  100,
  true
)

onMounted(() => {
  autoResetSize()
  window.addEventListener('resize', autoResetSize)
})

onUnmounted(() => {
  window.removeEventListener('resize', autoResetSize)
})

const setFormData = (newData: any) => {
  state.formdata = newData
}

const getFormData = () => {
  return modalFormParse.value?.getFormData()
}

const setFilterData = (newData: any) => {
  state.filterData = newData
}

const getFilterData = () => {
  return filterFormParse.value?.getFormData()
}

const setPageInfo = (page: number, size?: number) => {
  state.page = page
  state.size = size || 20
}

const addPageBtn = (pos: OperaBtnKeys, btn: BFCurdOperaBtn, index?: number) => {
  if (pos != 'modalCancelBtn' && pos != 'modalConfirmBtn') {
    index = index == undefined ? btns.value[pos].length : index
    btns.value[pos].splice(index, 0, btn)
  }
}

const updatePageBtn = (pos: OperaBtnKeys, index: number, newBtn: BFCurdOperaBtn) => {
  if (pos != 'modalCancelBtn' && pos != 'modalConfirmBtn') {
    btns.value[pos][index] = newBtn
  } else {
    btns.value[pos] = newBtn
  }
}

const deletePageBtn = (pos: OperaBtnKeys, index: number) => {
  if (pos != 'modalCancelBtn' && pos != 'modalConfirmBtn') {
    btns.value[pos].splice(index, 1)
  }
}

defineExpose<BFCurdExpose<any>>({
  showModal,
  hideModal,
  showFilter,
  hideFilter,
  setFormData,
  getFormData,
  setFilterData,
  getFilterData,
  setPageInfo,
  addPageBtn,
  updatePageBtn,
  deletePageBtn
})
</script>

<style scoped lang="scss">
:deep(.n-spin-content) {
  height: 100% !important;
}
</style>
